From 238ca03bd451220cc54549ac860b452766a2d9c4 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Mon, 17 Oct 2005 14:07:47 +0100 Subject: [PATCH] Replace xm vcpu-enable and xm vcpu-disable with one command, xm set-vcpus, which sets the number of active CPUs. Xend then toggles the VCPUs to ensure a contiguous group of them are enabled. Added a server command to get VCPU information, and use this info to fix xm vcpu-list. That xm command now has extra information, too. CPU == -1 is no longer used as an indicator for a VCPU that is disabled -- a separate state field is available, and the CPU is set merely to '-'. Individual CPU time is now available. Deprecated xm list -v. -v is conventionally used for --verbose, so using it to list vcpus is confusing. Furthermore, we already have an equivalent command xm vcpu-list. Tidied up the horrendous xm list / xm vcpu-list code. Removed the vcpus field from the dict returned by xc_domain_getinfo, and the vcpu_to_cpu map from the sxpr returned for xm list. Move the dom0_enforce_vcpus code into XendDomain. Signed-off-by: Ewan Mellor --- tools/python/xen/lowlevel/xc/xc.c | 7 +- tools/python/xen/xend/XendClient.py | 12 +- tools/python/xen/xend/XendDomain.py | 9 +- tools/python/xen/xend/XendDomainInfo.py | 119 +++++++------ tools/python/xen/xend/server/SrvDomain.py | 16 +- tools/python/xen/xm/main.py | 195 +++++++++++----------- 6 files changed, 193 insertions(+), 165 deletions(-) diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 38032042a2..4a11ef77c5 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -317,11 +317,9 @@ static PyObject *pyxc_domain_getinfo(PyObject *self, PyObject *pyhandle = PyList_New(sizeof(xen_domain_handle_t)); for ( j = 0; j < sizeof(xen_domain_handle_t); j++ ) PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j])); - info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" + info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" ",s:l,s:L,s:l,s:i,s:i}", "dom", info[i].domid, - /* XXX 'vcpus' field is obsolete! */ - "vcpus", info[i].nr_online_vcpus, "online_vcpus", info[i].nr_online_vcpus, "max_vcpu_id", info[i].max_vcpu_id, "dying", info[i].dying, @@ -980,8 +978,7 @@ static PyMethodDef pyxc_methods[] = { " maxmem_kb [int]: Maximum memory limit, in kilobytes\n" " cpu_time [long]: CPU time consumed, in nanoseconds\n" " shutdown_reason [int]: Numeric code from guest OS, explaining " - "reason why it shut itself down.\n" - " vcpu_to_cpu [[int]]: List that maps VCPUS to CPUS\n" }, + "reason why it shut itself down.\n" }, { "vcpu_getinfo", (PyCFunction)pyxc_vcpu_getinfo, diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 39c57dc8b8..22f8fc7571 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -199,6 +199,9 @@ class Xend: def xend_list_domains(self): return self.xendGet(self.domainurl(), {'detail': '1'}) + def xend_domain_vcpuinfo(self, dom): + return self.xendGet(self.domainurl(dom), {'op': 'vcpuinfo'}) + def xend_domain_create(self, conf): return self.xendPost(self.domainurl(), {'op' : 'create', @@ -286,11 +289,10 @@ class Xend: 'target' : mem_target }) return val - def xend_domain_vcpu_hotplug(self, id, vcpu, state): - return self.xendPost(self.domainurl(id), - {'op' : 'vcpu_hotplug', - 'vcpu' : vcpu, - 'state' : state }) + def xend_domain_set_vcpus(self, dom, vcpus): + return self.xendPost(self.domainurl(dom), + {'op' : 'set_vcpus', + 'vcpus' : vcpus }) def xend_domain_vif_limit(self, id, vif, credit, period): return self.xendPost(self.domainurl(id), diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index ce4007b984..6f1ab9b84e 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -129,7 +129,14 @@ class XendDomain: def dom0_setup(self): """Expects to be protected by the domains_lock.""" dom0 = self.domains[PRIV_DOMAIN] - dom0.dom0_enforce_vcpus() + + # get max number of vcpus to use for dom0 from config + target = int(xroot.get_dom0_vcpus()) + log.debug("number of vcpus to use is %d", target) + + # target == 0 means use all processors + if target > 0: + self.setVCpuCount(target) def _add_domain(self, info): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 9e98b2cb55..79fdd38a9a 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -133,8 +133,6 @@ ROUNDTRIPPING_CONFIG_ENTRIES = [ # its VCPUs. This is translated to # /cpu//availability = {online,offline} for use # by the guest domain. -# vcpu_to_cpu: the current mapping between virtual CPUs and the physical -# CPU it is using. # cpumap: a list of bitmaps, one for each VCPU, giving the physical # CPUs that that VCPU may use. # cpu: a configuration setting requesting that VCPU 0 is pinned to @@ -392,6 +390,8 @@ class XendDomainInfo: self.refresh_shutdown_lock = threading.Condition() + ## private: + def augmentInfo(self): """Augment self.info, as given to us through {@link #recreate}, with values taken from the store. This recovers those values known to xend @@ -544,25 +544,36 @@ class XendDomainInfo: def gatherVm(self, *args): return xstransact.Gather(self.vmpath, *args) + + ## public: + def storeVm(self, *args): return xstransact.Store(self.vmpath, *args) + + ## private: + def readDom(self, *args): return xstransact.Read(self.dompath, *args) def writeDom(self, *args): return xstransact.Write(self.dompath, *args) + + ## public: + def removeDom(self, *args): return xstransact.Remove(self.dompath, *args) - def gatherDom(self, *args): - return xstransact.Gather(self.dompath, *args) + + ## private: def storeDom(self, *args): return xstransact.Store(self.dompath, *args) + ## public: + def storeVmDetails(self): to_store = { 'uuid': self.uuid, @@ -596,18 +607,26 @@ class XendDomainInfo: if v: to_store[k] = str(v) + to_store.update(self.vcpuDomDetails()) + + log.debug("Storing domain details: %s", to_store) + + self.writeDom(to_store) + + + ## private: + + def vcpuDomDetails(self): def availability(n): if self.info['vcpu_avail'] & (1 << n): return 'online' else: return 'offline' + result = {} for v in range(0, self.info['vcpus']): - to_store["cpu/%d/availability" % v] = availability(v) - - log.debug("Storing domain details: %s", to_store) - - self.writeDom(to_store) + result["cpu/%d/availability" % v] = availability(v) + return result def setDomid(self, domid): @@ -635,9 +654,17 @@ class XendDomainInfo: def getUuid(self): return self.uuid + def getVCpuCount(self): return self.info['vcpus'] + + def setVCpuCount(self, vcpus): + self.info['vcpu_avail'] = (1 << vcpus) - 1 + self.storeVm('vcpu_avail', self.info['vcpu_avail']) + self.writeDom(self.vcpuDomDetails()) + + def getSsidref(self): return self.info['ssidref'] @@ -872,12 +899,12 @@ class XendDomainInfo: return self.getDeviceController(deviceClass).destroyDevice(devid) - ## private: - def getDeviceSxprs(self, deviceClass): return self.getDeviceController(deviceClass).sxprs() + ## private: + def getDeviceConfigurations(self, deviceClass): return self.getDeviceController(deviceClass).configurations() @@ -932,11 +959,6 @@ class XendDomainInfo: if self.infoIsSet('cpu_time'): sxpr.append(['cpu_time', self.info['cpu_time']/1e9]) sxpr.append(['vcpus', self.info['vcpus']]) - if self.infoIsSet('cpumap'): - sxpr.append(['cpumap', self.info['cpumap']]) - if self.infoIsSet('vcpu_to_cpu'): - sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]]) - sxpr.append(['vcpu_to_cpu', self.prettyVCpuMap()]) if self.infoIsSet('start_time'): up_time = time.time() - self.info['start_time'] @@ -951,12 +973,33 @@ class XendDomainInfo: return sxpr - ## private: - - def prettyVCpuMap(self): - return '|'.join(map(str, - self.info['vcpu_to_cpu'][0:self.info['vcpus']])) + def getVCPUInfo(self): + try: + # We include the domain name and ID, to help xm. + sxpr = ['domain', + ['domid', self.domid], + ['name', self.info['name']], + ['vcpu_count', self.info['vcpus']]] + + for i in range(0, self.info['vcpus']): + info = xc.vcpu_getinfo(self.domid, i) + + sxpr.append(['vcpu', + ['number', i], + ['online', info['online']], + ['blocked', info['blocked']], + ['running', info['running']], + ['cpu_time', info['cpu_time'] / 1e9], + ['cpu', info['cpu']], + ['cpumap', info['cpumap']]]) + + return sxpr + + except RuntimeError, exn: + raise XendError(str(exn)) + + ## private: def check_name(self, name): """Check if a vm name is valid. Valid names contain alphabetic characters, @@ -1335,22 +1378,6 @@ class XendDomainInfo: xc.domain_setmaxmem(self.domid, maxmem_kb = m) - def vcpu_hotplug(self, vcpu, state): - """Disable or enable VCPU in domain. - """ - if vcpu > self.info['vcpus']: - log.error("Invalid VCPU %d" % vcpu) - return - if int(state) == 0: - self.info['vcpu_avail'] &= ~(1 << vcpu) - availability = "offline" - else: - self.info['vcpu_avail'] &= (1 << vcpu) - availability = "online" - self.storeVm('vcpu_avail', self.info['vcpu_avail']) - self.storeDom("cpu/%d/availability" % vcpu, availability) - - def send_sysrq(self, key): asserts.isCharConvertible(key) @@ -1371,24 +1398,6 @@ class XendDomainInfo: raise - def dom0_enforce_vcpus(self): - dom = 0 - # get max number of vcpus to use for dom0 from config - target = int(xroot.get_dom0_vcpus()) - log.debug("number of vcpus to use is %d", target) - - # target = 0 means use all processors - if target > 0: - # count the number of online vcpus (cpu values in v2c map >= 0) - vcpus_online = dom_get(dom)['vcpus'] - log.debug("found %d vcpus online", vcpus_online) - - # disable any extra vcpus that are online over the requested target - for vcpu in range(target, vcpus_online): - log.info("enforcement is disabling DOM%d VCPU%d", dom, vcpu) - self.vcpu_hotplug(vcpu, 0) - - def infoIsSet(self, name): return name in self.info and self.info[name] is not None diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 535d9323f4..5278506cc4 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -165,17 +165,25 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.domid}) return val - def op_vcpu_hotplug(self, op, req): - return self.call(self.dom.vcpu_hotplug, - [['vcpu', 'int'], - ['state', 'int']], + def op_set_vcpus(self, op, req): + return self.call(self.dom.setVCpuCount, + [['vcpus', 'int']], req) + + def op_vcpuinfo(self, _1, req): + return self.call(self.dom.getVCPUInfo, [], req) + + def render_POST(self, req): return self.perform(req) def render_GET(self, req): op = req.args.get('op') + + if op and op[0] in ['vcpuinfo']: + return self.perform(req) + # # XXX SMH: below may be useful once again if we ever try to get # the raw 'web' interface to xend working once more. But for now diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index a3e35f993b..e2545c53cd 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -71,8 +71,7 @@ longhelp = """Usage: xm [args] xm full list of subcommands: Domain Commands: - console attach to console of DomId - cpus-list get the list of cpus for a VCPU + console attach to console of DomId create create a domain destroy terminate a domain immediately domid convert a domain name to a domain id @@ -88,10 +87,9 @@ xm full list of subcommands: shutdown [-w|-a] shutdown a domain sysrq send a sysrq to a domain unpause unpause a paused domain - vcpu-enable enable VCPU in a domain - vcpu-disable disable VCPU in a domain - vcpu-list get the list of VCPUs for a domain - vcpu-pin set which cpus a VCPU can use. + set-vcpus enable the specified number of VCPUs in a domain + vcpu-list list the VCPUs for a domain + vcpu-pin set which cpus a VCPU can use. Xen Host Commands: dmesg [--clear] read or clear Xen's message buffer @@ -209,6 +207,15 @@ def xm_restore(args): if id is not None: server.xend_domain_unpause(domid) + +def getDomains(domain_names): + from xen.xend.XendClient import server + if domain_names: + return map(server.xend_domain, domain_names) + else: + return server.xend_list_domains() + + def xm_list(args): use_long = 0 show_vcpus = 0 @@ -218,80 +225,105 @@ def xm_list(args): err(opterr) sys.exit(1) - n = len(params) for (k, v) in options: if k in ['-l', '--long']: use_long = 1 if k in ['-v', '--vcpus']: show_vcpus = 1 - from xen.xend.XendClient import server - if n == 0: - doms = server.xend_list_domains() - else: - doms = map(server.xend_domain, params) - + if show_vcpus: + print >>sys.stderr, ( + "xm list -v is deprecated. Please use xm vcpu-list.") + xm_vcpu_list(params) + return + + doms = getDomains(params) + if use_long: - for dom in doms: - PrettyPrint.prettyprint(dom) + map(PrettyPrint.prettyprint, doms) else: - domsinfo = map(parse_doms_info, doms) + xm_brief_list(doms) - if show_vcpus: - xm_show_vcpus(domsinfo) - else: - xm_brief_list(domsinfo) def parse_doms_info(info): - dominfo = {} - dominfo['dom'] = int(sxp.child_value(info, 'domid', '-1')) - dominfo['name'] = sxp.child_value(info, 'name', '??') - dominfo['mem'] = int(sxp.child_value(info, 'memory', '0')) - dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0')) - dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0')) - # if there is more than 1 cpu, the value doesn't mean much - if dominfo['vcpus'] > 1: - dominfo['cpu'] = '-' - dominfo['state'] = sxp.child_value(info, 'state', '??') - dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0')) - # security identifiers - if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0): - dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff - dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff - # get out the vcpu information - dominfo['vcpulist'] = [] - vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|') - cpumap = sxp.child_value(info, 'cpumap', []) - mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1 - count = 0 - for cpu in vcpu_to_cpu: - vcpuinfo = {} - vcpuinfo['name'] = sxp.child_value(info, 'name', '??') - vcpuinfo['dom'] = int(sxp.child_value(info, 'domid', '-1')) - vcpuinfo['vcpu'] = int(count) - vcpuinfo['cpu'] = int(cpu) - #vcpuinfo['cpumap'] = int(cpumap[count])&mask - count = count + 1 - #dominfo['vcpulist'].append(vcpuinfo) - return dominfo - -def xm_brief_list(domsinfo): - print 'Name ID Mem(MiB) CPU VCPUs State Time(s)' - for dominfo in domsinfo: - if dominfo.has_key("ssidref1"): - print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo) + def get_info(n, t, d): + return t(sxp.child_value(info, n, d)) + + return { + 'dom' : get_info('domid', int, -1), + 'name' : get_info('name', str, '??'), + 'mem' : get_info('memory', int, 0), + 'vcpus' : get_info('vcpus', int, 0), + 'state' : get_info('state', str, '??'), + 'cpu_time' : get_info('cpu_time', float, 0), + 'ssidref' : get_info('ssidref', int, 0), + } + + +def xm_brief_list(doms): + print 'Name ID Mem(MiB) VCPUs State Time(s)' + for dom in doms: + d = parse_doms_info(dom) + if (d['ssidref'] != 0): + d['ssidstr'] = (" s:%04x/p:%04x" % + ((d['ssidref'] >> 16) & 0xffff, + d['ssidref'] & 0xffff)) else: - print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo) + d['ssidstr'] = "" + print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f%(ssidstr)s" % d) -def xm_show_vcpus(domsinfo): - print 'Name Id VCPU CPU CPUMAP' - for dominfo in domsinfo: - for vcpuinfo in dominfo['vcpulist']: - print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" % - vcpuinfo) def xm_vcpu_list(args): - xm_list(["-v"] + args) + print 'Name ID VCPU CPU State Time(s) CPU Map' + + from xen.xend.XendClient import server + if args: + dominfo = map(server.xend_domain_vcpuinfo, args) + else: + doms = server.xend_list_domains() + dominfo = map( + lambda x: server.xend_domain_vcpuinfo(sxp.child_value(x, 'name')), + doms) + + for dom in dominfo: + def get_info(n): + return sxp.child_value(dom, n) + + name = get_info('name') + domid = int(get_info('domid')) + + + for vcpu in sxp.children(dom, 'vcpu'): + def vinfo(n, t): + return t(sxp.child_value(vcpu, n)) + + number = vinfo('number', int) + cpu = vinfo('cpu', int) + cpumap = vinfo('cpumap', int) + online = vinfo('online', int) + cpu_time = vinfo('cpu_time', float) + running = vinfo('running', int) + blocked = vinfo('blocked', int) + + if online: + c = str(cpu) + if running: + s = 'r' + else: + s = '-' + if blocked: + s += 'b' + else: + s += '-' + s += '-' + else: + c = "-" + s = "--p" + + print ( + "%(name)-32s %(domid)3d %(number)4d %(c)3s %(s)-3s %(cpu_time)7.1f 0x%(cpumap)x" % + locals()) + def xm_reboot(args): arg_check(args,1,"reboot") @@ -338,8 +370,6 @@ def cpu_make_map(cpulist): return cpumap def xm_vcpu_pin(args): - arg_check(args, 3, "vcpu-pin") - dom = args[0] vcpu = int(args[1]) cpumap = cpu_make_map(args[2]) @@ -348,8 +378,6 @@ def xm_vcpu_pin(args): server.xend_domain_pincpu(dom, vcpu, cpumap) def xm_mem_max(args): - arg_check(args, 2, "mem-max") - dom = args[0] mem = int_unit(args[1], 'm') @@ -357,36 +385,15 @@ def xm_mem_max(args): server.xend_domain_maxmem_set(dom, mem) def xm_mem_set(args): - arg_check(args, 2, "mem-set") - dom = args[0] mem_target = int_unit(args[1], 'm') from xen.xend.XendClient import server server.xend_domain_mem_target_set(dom, mem_target) -# TODO: why does this lookup by name? and what if that fails!? -def xm_vcpu_enable(args): - arg_check(args, 2, "vcpu-enable") - - name = args[0] - vcpu = int(args[1]) - +def xm_set_vcpus(args): from xen.xend.XendClient import server - dom = server.xend_domain(name) - id = sxp.child_value(dom, 'domid') - server.xend_domain_vcpu_hotplug(id, vcpu, 1) - -def xm_vcpu_disable(args): - arg_check(args, 2, "vcpu-disable") - - name = args[0] - vcpu = int(args[1]) - - from xen.xend.XendClient import server - dom = server.xend_domain(name) - id = sxp.child_value(dom, 'domid') - server.xend_domain_vcpu_hotplug(id, vcpu, 0) + server.xend_domain_set_vcpus(args[0], int(args[1])) def xm_domid(args): name = args[0] @@ -586,9 +593,7 @@ commands = { "mem-set": xm_mem_set, # cpu commands "vcpu-pin": xm_vcpu_pin, -# "cpus-list": xm_cpus_list, - "vcpu-enable": xm_vcpu_enable, - "vcpu-disable": xm_vcpu_disable, + "set-vcpus": xm_set_vcpus, "vcpu-list": xm_vcpu_list, # special "pause": xm_pause, -- 2.30.2